/**
 * Copyright (c) 2009 Collaborative Development Group, C.S. Dept., University of Bari
 *
 * All rights reserved. This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License v1.0  which accompanies this distribution, and is 
 * available at http://www.eclipse.org/legal/epl-v10.html
 */
package it.uniba.di.cdg.penelope.events;

import static it.uniba.di.cdg.penelope.events.IEventHelper.APP_EVENT;

import java.lang.reflect.Method;
import java.util.List;

import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;

import com.google.inject.Inject;


/**
 * Proxy to wrap around objects that contain methods marked with {@link OnEvent} annotation,
 */
public class EventHandlerProxy implements EventHandler {

	private final Object delegate;
	private IEventHandlerProxyFactory factory;

	/**
	 * {@link EventHandlerProxy} are built by {@link IEventHandlerProxyFactory#get(Object)}.
	 * @param factory
	 * @param delegate
	 */
	@Inject
	/* package */ EventHandlerProxy( IEventHandlerProxyFactory factory, Object delegate ) {
		this.factory = factory;
		this.delegate = delegate;
	}

	/* (non-Javadoc)
	 * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)
	 */
	@Override
	public void handleEvent( Event event ) {
		Object applicationEvent = getApplicationEvent( event );
		if (applicationEvent == null)
			return;
		// Dispath the event to the appropriate methods.
		List<Method> methods = factory.getMethods( delegate.getClass() );
		for (Method method : methods) {
			//OnEvent ann = method.getAnnotation( OnEvent.class );

			Class<?> targetEventClass = null;
			if (method.getParameterTypes().length == 1) {
				targetEventClass = method.getParameterTypes()[0];
			} else {
				throw new EventHandlerInvocationException( "Only a method with an event parameter can be annotated with @OnEvent!" );
			}
			
			if (applicationEvent.getClass().equals( targetEventClass )) {
				try {
					method.invoke( delegate, applicationEvent );
				} catch (Throwable e) {
					throw new EventHandlerInvocationException( e );
				}
			}
		}
	}

	/**
	 * @param event
	 * @return
	 */
	private Object getApplicationEvent( Event event ) {
		return event.getProperty( APP_EVENT );
	}
}